package com.cjd.common.model

import android.content.Context
import android.os.Handler
import android.os.Looper
import com.cjd.common.utils.LogUtils
import java.lang.ref.WeakReference
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

/**
 * @Author chenjidong
 * @email 374122600@qq.com
 * created 2019/9/22
 * description 业务逻辑model
 */
abstract class BaseModel<T : IBaseModel>(val t: T) {

    private var context: Context? = null
    private var iModel: T? = null
    private var weakReference: WeakReference<T>? = null
    private var handler: Handler? = null

    private val executorService: ExecutorService by lazy {
        Executors.newSingleThreadExecutor()
    }

    fun runOnUiThread(block: () -> Unit) {
        handler?.post {
            block()
        }
    }

    fun runOnJobThread(block: () -> Unit) {
        executorService.execute {
            block()
        }
    }

    private fun getProxy(t: T) = Proxy.newProxyInstance(
        t.javaClass.classLoader,
        t.javaClass.interfaces,
        ProxyIModel(t)
    ) as T

    open fun onViewCreated() {
        handler = Handler(Looper.getMainLooper())
        iModel = getProxy(t)
        weakReference = WeakReference(iModel!!)

        getIModel()?.onStart()
        if (LogUtils.isDebuggable()) {
            onStart()
        } else {
            try {
                onStart()
            } catch (e: Exception) {
                e.message?.let {
                    LogUtils.e(it)
                }
                getIModel()?.onError(e.message)
            }
        }
    }

    open fun onViewResume() {

    }

    open fun onViewPause() {

    }

    open fun onViewAttach(context: Context) {

    }

    open fun getIModel(): T? {
        return iModel
    }

    fun isDestroy() = weakReference == null || weakReference?.get() == null

    open fun onViewDestroy() {
        handler?.removeCallbacksAndMessages(null)
        getIModel()?.onDestroy()
        if (!isDestroy()) {
            weakReference?.clear()
            weakReference = null
        }
        executorService?.let {
            it.shutdown()
        }
    }

    abstract fun onStart()

    inner class ProxyIModel(private val target: Any) : InvocationHandler {
        override fun invoke(obj: Any?, method: Method, args: Array<out Any>?): Any? {

            if (isDestroy()) {
                LogUtils.d("--->${method.name}")
                return null
            }
            return method.invoke(target, *(args ?: arrayOfNulls<Any>(0)))
        }
    }
}